<?php

namespace App\Http\Middleware;

use App\Exceptions\LoginException;
use App\Exceptions\SuperAdminException;
use App\Helpers\MvcHelper;
use App\Services\User\UserService;
use Closure;
use Exception;
use Illuminate\Http\Request;

class AuthenticateMiddleware
{
    /**
     * @throws LoginException
     * @throws Exception
     */
    public function handle(Request $request, Closure $next)
    {
        $request->merge(['custom_param' => 'value_from_middleware']);
        $token = MvcHelper::getLoginToken();
        // 判断 token 是否有效
        $userInfo = verifyJwt($token);
        // 检测用户是否存在
        $userData = $this->getUserService()->getCheckUserInfo($userInfo['userId']);
        if (empty($userData)) {
            throw new LoginException('登录状态失效，请重新登录', LoginException::CODE_1000);
        }

        // 暂存token过期时间(为了全局获取，退出登录时加入jwt黑名单用)
        MvcHelper::makeLoginTokenExpire($userInfo['exp']);

        // 检测用户是否禁用
        if ($this->getUserService()->checkForbidden($userData['enable'])) {
            throw new LoginException('非法用户，请联系客服检查用户状态', LoginException::CODE_1003);
        }

        // 接口路径
        $path = $request->decodedPath();

        // 检查接口权限
        if (!$this->checkApiAuth($userData['authority_id'], $path)) {
            throw new SuperAdminException("没有接口权限", SuperAdminException::CODE_2000);
        }

        // 设置用户缓存
        MvcHelper::setUserInfCache($userData);

        return $next($request);
    }

    /**
     * @return UserService
     */
    private function getUserService(): UserService
    {
        return loadService('User\UserService');
    }

    private function checkApiAuth(int $authorityId, string $path): bool
    {
        // @tips 接口权限白名单
        $apiAuthWhiteList = [
            'api/user/login',
            'api/user/userInfo',
            'api/user/captcha',
            'api/user/logout',
            'api/server/tencent/getUploadToken',
            'api/user/setSelfInfo',
            'api/user/changePassword',
        ];
        if (in_array($path, $apiAuthWhiteList)) {
            return true;
        }

        if (empty($authorityId)) {
            return false;
        }
        $apis = $this->getUserService()->getApisPathByAuthorityId($authorityId);
        if (empty($apis)) {
            return false;
        }

        return in_array(DIRECTORY_SEPARATOR . $path, $apis);
    }

}
